package edu.nus.cs4243.recon.utils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import Jama.EigenvalueDecomposition;
import Jama.Matrix;

/**
 * Wraps JAMA into vecmath matrices
 * 
 * @author johannes
 */
public class MatrixUtils {

	/**
	 * Compute eigenvectors and eigenvalues of a (symmetric) matrix.
	 * 
	 * @param m
	 *            the matrix to find the eigenvalues and eigenvectors of. All the eigenvalues must
	 *            be real.
	 * @return eigenvalues and eigenvectors as column vectors
	 */
	public static Pair<double[], Matrix[]> eig(Matrix m) {
		EigenvalueDecomposition ev = new EigenvalueDecomposition(m);
		Pair<double[], Matrix[]> result = new Pair<double[], Matrix[]>();
		result.a = ev.getRealEigenvalues();
		Matrix eigvs = ev.getV();
		result.b = new Matrix[eigvs.getColumnDimension()];
		double[] eigvsCols = eigvs.getColumnPackedCopy();
		double[] oneColumn = new double[eigvs.getRowDimension()];
		for (int i = 0; i < eigvs.getColumnDimension(); i++) {
			System.arraycopy(eigvsCols, i * oneColumn.length, oneColumn, 0, oneColumn.length);
			result.b[i] = new Matrix(oneColumn.length, 1);
			for (int row = 0; row < oneColumn.length; row++) {
				result.b[i].set(row, 0, oneColumn[row]);
			}
		}
		return result;
	}

	/**
	 * <p>
	 * Load a matrix from a text file.
	 * </p>
	 * <p>
	 * The order of the numbers in the array is the same as the order in the text file.
	 * </p>
	 * 
	 * @param file
	 *            the file to load the matrix from
	 * @throws IOException
	 */
	public static double[] loadMatrix(File file) throws IOException {
		return loadMatrix(file, ",");
	}

	/**
	 * <p>
	 * Load a matrix from a text file.
	 * </p>
	 * <p>
	 * The order of the numbers in the array is the same as the order in the text file.
	 * </p>
	 * 
	 * @param file
	 *            the file to load the matrix from
	 * @param separator
	 *            the separator between columns
	 * @throws IOException
	 */
	public static double[] loadMatrix(File file, String separator) throws IOException {
		BufferedReader in = null;
		try {
			in = new BufferedReader(new FileReader(file));
			String line;
			List<String[]> lines = new ArrayList<String[]>();
			while ((line = in.readLine()) != null) {
				lines.add(line.split(separator));
				if (lines.get(lines.size() - 1).length != lines.get(0).length)
					throw new IOException("Invalid matrix!");
			}
			double[] result = new double[lines.size() * lines.get(0).length];
			int k = 0;
			for (String[] row : lines) {
				for (int j = 0; j < row.length; j++) {
					result[k++] = Double.valueOf(row[j].trim());
				}
			}
			return result;
		} finally {
			if (in != null)
				in.close();
		}
	}

	public static String matrixToString(Matrix m) {
		StringBuilder result = new StringBuilder();

		for (int row = 0; row < m.getRowDimension(); row++) {
			for (int col = 0; col < m.getColumnDimension(); col++) {
				result.append(String.format("%10.5f ", m.get(row, col)));
			}
			result.append("\n");
		}

		return result.toString();
	}

}
